home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************
-
-
- File: ShapeMeasurement.c
-
- This file contains utilities that can more accurately measure
- shapes than the functions built into QuickDraw GX. While the
- functions in GX are accurate enough for doing normal dashing of
- shapes, the slight errors are visually obvious when using them
- for text positioning.
-
- Much thanks to Joseph Maurer for implementing the hard-core
- math part of this.
-
- ************************************************************/
-
-
-
-
- #include "Types.h"
- #include "GXTypes.h"
- #include "GXMath.h"
- #include "GXGraphics.h"
- #include "GXLayout.h"
- #include "GXExceptions.h"
-
- #include "ComputeLength.h"
-
- #include "PathWalking.h"
- #include "AccurateShapes.h"
-
-
- /****
- Structure for state required
- when computing ShapeLengthToPoint
- ****/
-
- typedef struct {
-
- gxPoint currentPoint; // the current point in our state.
- gxPoint firstPoint; // the first point in the current contour.
- long currentContour; // the contour we are currently looking at.
- long desiredContour; // the contour we are interested in. (zero means all contours)
- double desiredLength; // the length we are after.
- double currentLength; // cache of current length;
-
- gxPoint location; // we'll put the position we find here.
- gxPoint tangent; // the tangent point will end up here.
-
- } TShapeLenRec;
-
-
- /* Callback routines for ShapeLengthToPoint */
-
-
-
- Boolean ShapeLenToPtMoveto(gxPoint *p, TShapeLenRec* pWalk);
- Boolean ShapeLenToPtMoveto(gxPoint *p, TShapeLenRec* pWalk)
- {
-
- pWalk->currentPoint.x = p->x;
- pWalk->currentPoint.y = p->y;
- pWalk->firstPoint.x = p->x;
- pWalk->firstPoint.y = p->y;
-
- pWalk->currentContour += 1;
-
- /* if we've passed the desired contour, stop early */
-
- if ( (pWalk->desiredContour != 0 ) && (pWalk->currentContour > pWalk->desiredContour) )
- return(true);
- else
- return(false);
- }
-
-
-
- Boolean ShapeLenToPtLineto(gxPoint *p, TShapeLenRec* pWalk);
- Boolean ShapeLenToPtLineto(gxPoint *p, TShapeLenRec* pWalk)
- {
- gxLine aLine;
- Boolean stop = false;
- double segmentLength;
-
-
- aLine.first.x = pWalk->currentPoint.x;
- aLine.first.y = pWalk->currentPoint.y;
- aLine.last.x = p->x;
- aLine.last.y = p->y;
-
- pWalk->currentPoint.x = p->x;
- pWalk->currentPoint.y = p->y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetLineLength(&aLine);
-
- /* if we've exceeded the desired length, then we're on the correct segment */
-
- if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
-
- /* find the point on this segment that is the length we want */
-
- LineLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aLine, &(pWalk->location), &(pWalk->tangent) );
-
- stop = true;
-
- }//end if
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(stop);
- }
-
-
-
- Boolean ShapeLenToPtCurveto(gxPoint p[3], TShapeLenRec* pWalk);
- Boolean ShapeLenToPtCurveto(gxPoint p[3], TShapeLenRec* pWalk)
- {
- gxCurve aCurve;
- Boolean stop = false;
- double segmentLength;
-
- aCurve.first.x = p[0].x;
- aCurve.first.y = p[0].y;
- aCurve.control.x = p[1].x;
- aCurve.control.y = p[1].y;
- aCurve.last.x = p[2].x;
- aCurve.last.y = p[2].y;
-
- pWalk->currentPoint.x = p[2].x;
- pWalk->currentPoint.y = p[2].y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetCurveLength(&aCurve);
-
- /* if we've exceeded the desired length, then we're on the correct segment */
-
- if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
-
- /* find the point on this segment that is the length we want */
-
- CurveLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aCurve, &(pWalk->location), &(pWalk->tangent) );
-
- stop = true;
-
- }//end if
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(stop);
- }
-
-
-
- Boolean ShapeLenToPtClosepath( TShapeLenRec* pWalk);
- Boolean ShapeLenToPtClosepath( TShapeLenRec* pWalk)
- {
- Boolean stop = false;
- gxLine aLine;
- double segmentLength;
-
- aLine.first.x = pWalk->currentPoint.x;
- aLine.first.y = pWalk->currentPoint.y;
- aLine.last.x = pWalk->firstPoint.x;
- aLine.last.y = pWalk->firstPoint.y;
-
- pWalk->currentPoint.x = pWalk->firstPoint.x;
- pWalk->currentPoint.y = pWalk->firstPoint.y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetLineLength(&aLine);
-
- /* if we've exceeded the desired length, then we're on the correct segment */
-
- if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
-
- /* find the point on this segment that is the length we want */
-
- LineLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aLine, &(pWalk->location), &(pWalk->tangent) );
-
- stop = true;
-
- }//end if
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(stop);
- }
-
-
-
-
- /*****************************************
-
- Routine: AccurateShapeLengthToPoint.
-
- Replacement for GXShapeLengthToPoint.
-
- ******************************************/
-
- gxPoint* AccurateShapeLengthToPoint(gxShape target, long index, Fixed length, gxPoint *location, gxPoint *tangent)
- {
- Boolean stoppedEarly;
- TShapeLenRec shapeLenRec;
- gxPoint *result;
-
- result = location;
-
- /* initialize the structure that maintains our state. */
-
- shapeLenRec.currentContour = 0;
- shapeLenRec.desiredContour = index;
- shapeLenRec.currentLength = 0.0;
- shapeLenRec.desiredLength = FixedToDouble(length);
-
- /* Now walk the shape using our shape length calculation callbacks. */
-
- stoppedEarly = ShapeWalker(target, ShapeLenToPtMoveto, ShapeLenToPtLineto, ShapeLenToPtCurveto, ShapeLenToPtClosepath, &shapeLenRec);
-
- /* if we didn't stop early, then the walker got to the end of the shape without finding the answer */
-
- if (stoppedEarly) {
-
- if (location) {
- location->x = shapeLenRec.location.x;
- location->y = shapeLenRec.location.y;
- }
-
- if (tangent) {
- tangent->x = shapeLenRec.tangent.x;
- tangent->y = shapeLenRec.tangent.y;
- }
-
- } else {
-
- GXPostGraphicsError(length_out_of_range);
-
- }//end if
-
- return(result);
-
- }//AccurateShapeLengthToPoint
-
-
-
-
- /****** callback Routines for computing total length of the shape *****/
-
- Boolean ShapeLenMoveto(gxPoint *p, TShapeLenRec* pWalk);
- Boolean ShapeLenMoveto(gxPoint *p, TShapeLenRec* pWalk)
- {
-
- pWalk->currentPoint.x = p->x;
- pWalk->currentPoint.y = p->y;
- pWalk->firstPoint.x = p->x;
- pWalk->firstPoint.y = p->y;
-
- pWalk->currentContour += 1;
-
- /* if we've passed the desired contour, stop early */
-
- if ( (pWalk->desiredContour != 0 ) && (pWalk->currentContour > pWalk->desiredContour) )
- return(true);
- else
- return(false);
- }
-
-
-
- Boolean ShapeLenLineto(gxPoint *p, TShapeLenRec* pWalk);
- Boolean ShapeLenLineto(gxPoint *p, TShapeLenRec* pWalk)
- {
- gxLine aLine;
- double segmentLength;
-
- aLine.first.x = pWalk->currentPoint.x;
- aLine.first.y = pWalk->currentPoint.y;
- aLine.last.x = p->x;
- aLine.last.y = p->y;
-
- pWalk->currentPoint.x = p->x;
- pWalk->currentPoint.y = p->y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetLineLength(&aLine);
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(false);
- }
-
-
-
- Boolean ShapeLenCurveto(gxPoint p[3], TShapeLenRec* pWalk);
- Boolean ShapeLenCurveto(gxPoint p[3], TShapeLenRec* pWalk)
- {
- gxCurve aCurve;
- double segmentLength;
-
- aCurve.first.x = p[0].x;
- aCurve.first.y = p[0].y;
- aCurve.control.x = p[1].x;
- aCurve.control.y = p[1].y;
- aCurve.last.x = p[2].x;
- aCurve.last.y = p[2].y;
-
- pWalk->currentPoint.x = p[2].x;
- pWalk->currentPoint.y = p[2].y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetCurveLength(&aCurve);
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(false);
- }
-
-
-
- Boolean ShapeLenClosepath( TShapeLenRec* pWalk);
- Boolean ShapeLenClosepath( TShapeLenRec* pWalk)
- {
- gxLine aLine;
- double segmentLength;
-
- aLine.first.x = pWalk->currentPoint.x;
- aLine.first.y = pWalk->currentPoint.y;
- aLine.last.x = pWalk->firstPoint.x;
- aLine.last.y = pWalk->firstPoint.y;
-
- pWalk->currentPoint.x = pWalk->firstPoint.x;
- pWalk->currentPoint.y = pWalk->firstPoint.y;
-
- if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour) ) {
-
- segmentLength = GetLineLength(&aLine);
-
- pWalk->currentLength += segmentLength;
-
- }//end if
-
- return(false);
- }
-
-
-
-
-
- /*****************************************
-
- Routine: AccurateGetShapeLength.
-
- Replacement for GXGetShapeLength.
-
- ******************************************/
-
- wide* AccurateGetShapeLength(gxShape target, long index, wide *wideLength)
- {
- Boolean stoppedEarly;
- TShapeLenRec shapeLenRec;
- wide *result = wideLength;
-
- /* initialize the structure that maintains our state. */
-
- shapeLenRec.currentContour = 0;
- shapeLenRec.desiredContour = index;
- shapeLenRec.currentLength = 0.0;
-
- /* Now walk the shape using our shape length calculation callbacks. */
-
- stoppedEarly = ShapeWalker(target, ShapeLenMoveto, ShapeLenLineto, ShapeLenCurveto, ShapeLenClosepath, &shapeLenRec);
-
- /* Make a wide number out of the resulting length which is a double */
-
- if ( (shapeLenRec.currentLength < 32767.9999) && (shapeLenRec.currentLength > -32768.9999)) {
-
- double loPart, hiPart;
-
- loPart = shapeLenRec.currentLength;
-
- // sign extend the lo part into the high part.
- if (loPart > 0)
- hiPart = 0.0;
- else
- hiPart = -1.0;
-
- result->lo = DoubleToFixed(loPart);
- result->hi = (long)hiPart;
-
- } else {
-
- DebugStr("\pI don't know how to convert a big number to a wide ");
-
- }//end if
-
-
- return(result);
-
- }//AccurateGetShapeLength
-
-